﻿using System;
using System.Diagnostics;
using System.Threading;

using DanielVaughan.Logging.Tests.Mocks;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DanielVaughan.Logging.Tests
{
	/// <summary>
	///This is a test class for Log and is intended
	///to contain all Log Unit Tests
	///</summary>
	[TestClass]
	public class LogConcurrencyTests
	{
		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext { get; set; }

		static readonly MockLogStrategy strategy = new MockLogStrategy();

		[ClassInitialize]
		public static void ClassInitialize(TestContext testContext)
		{
			Log.LogRepository.AddLogStrategy("MockStrategy", strategy, null);
		}

		[TestMethod]
		public void LogShouldWriteEntry()
		{
			var resetEvent = new ManualResetEvent(false);
			Log.Write += delegate(object sender, LogEventArgs e) { resetEvent.Set(); };
			Log.Error("Test");
			resetEvent.WaitOne(5000);
			Assert.IsNotNull(strategy.ServerLogEntry);
		}

		[TestMethod]
		public void LogShouldWriteEntriesConcurrently()
		{
			int iterations = 1000;

			var events = new AutoResetEvent[iterations];
			var entries = new IServerLogEntry[iterations];

			for (int i = 0; i < iterations; i++)
			{
				events[i] = new AutoResetEvent(false);
			}

			AutoResetEvent resetEvent = new AutoResetEvent(false);
			long count = 0;
			Log.Write += delegate(object sender, LogEventArgs e)
			             	{
			             		long c = Interlocked.Read(ref count);
			             		IServerLogEntry entry = strategy.ServerLogEntry;
			             		entries[c] = entry;
			             		Interlocked.Increment(ref count);
			             		events[c].Set();
								if (c > iterations - 2)
								{
									resetEvent.Set();
								}
			             	};

			DateTime beginTime = DateTime.Now;
			for (int i = 0; i < iterations; i++)
			{
				Log.Error("Test " + i);
			}
			resetEvent.WaitOne(15000);
//			foreach (AutoResetEvent resetEvent in events)
//			{
//				resetEvent.WaitOne(15000);
//			}

			TimeSpan duration = DateTime.Now - beginTime;
			Debug.WriteLine(string.Format("LogShouldWriteEntriesConcurrently Duration for {0} iterations was {1}", iterations, duration));
			
			Assert.IsNotNull(strategy.ServerLogEntry);
		}
	}
}
